package by.bsu.diploma.temp;

import java.util.*;

/**
 * @author Anatoly Selitsky
 */
public class GeneratorCrossword {

    public static final int NOT_AVAILABLE = 2;

    public static final int ROW_COUNT = 4;
    public static final int COLUMN_COUNT = 4;
    public static int grid[][] = new int[ROW_COUNT][COLUMN_COUNT];

    private int quantity = 0;

    public void generate(List<WordSettings> wordSettings) {
        Collections.sort(wordSettings);
        Map<Integer, Integer> history = new HashMap<Integer, Integer>();
        populate(wordSettings, history);
    }

    public void populate(List<WordSettings> wordSettings, Map<Integer, Integer> history) {
        Random random = new Random();
        int row, col, length;
        for (WordSettings ws : wordSettings) {
            length = ws.getLength();
            for (int i = 0; i < ws.getCount(); i++) {
                if (history.containsKey(ws.getLength())) {
                    if (history.get(ws.getLength()) == ws.getCount()) {
                        break;
                    }
                }
                row = random.nextInt(ROW_COUNT);
                col = random.nextInt(COLUMN_COUNT);
                if (row + length - 1 < ROW_COUNT) {
                    if (isNotFoundRestriction(row, col, length, Orientation.VERTICAL)) {
                        if (populate(row, col, length, Orientation.VERTICAL)) {
                            updateHistory(history, ws);
                        } else {
                            populate(wordSettings, history);
                        }
                    } else {
                        populate(wordSettings, history);
                    }
                } else if (row - length + 1 >= 0) {
                    row = row - length + 1;
                    if (isNotFoundRestriction(row, col, length, Orientation.VERTICAL)) {
                        if (populate(row, col, length, Orientation.VERTICAL)) {
                            updateHistory(history, ws);
                        } else {
                            populate(wordSettings, history);
                        }
                    } else {
                        populate(wordSettings, history);
                    }
                } else if (col + length - 1 < COLUMN_COUNT) {
                    if (isNotFoundRestriction(row, col, length, Orientation.HORIZONTAL)) {
                        if (populate(row, col, length, Orientation.HORIZONTAL)) {
                            updateHistory(history, ws);
                        } else {
                            populate(wordSettings, history);
                        }
                    } else {
                        populate(wordSettings, history);
                    }
                } else if (col - length + 1 >= 0) {
                    col = col - length + 1;
                    if (isNotFoundRestriction(row, col, length, Orientation.HORIZONTAL)) {
                        if (populate(row, col, length, Orientation.HORIZONTAL)) {
                            updateHistory(history, ws);
                        } else {
                            populate(wordSettings, history);
                        }
                    } else {
                        populate(wordSettings, history);
                    }
                } else {
                    populate(wordSettings, history);
                }
            }
        }
    }

    public void updateHistory(Map<Integer, Integer> history, WordSettings wordSettings) {
        Integer key = wordSettings.getLength();
        if (history.containsKey(key)) {
            history.put(key, history.get(key) + 1);
        } else {
            history.put(key, 1);
        }
    }

    public boolean populate(int row, int col, int length, Orientation orientation) {
        boolean hasCrossing = false;
        if (Orientation.VERTICAL.equals(orientation)) {
            /*int count = 0;
            for (int k = row; k < row + length; k++) {
                if (grid[k][col] == 1 || grid[k][col] == -1) {
                    count++;
                }
            }
            if (count == 0) {
                return false;
            }*/
            for (int i = row; i < row + length; i++) {
                if (grid[i][col] == 1 || grid[i][col] == -1) {
                    grid[i][col] = -1;
                    hasCrossing = true;
                    addRestriction(i, col);
                } else {
                    grid[i][col] = 1;
                }
            }
            quantity++;
        } else {
            /*int count = 0;
            for (int i = col; i < col + length; i++) {
                if (grid[row][i] == 1 || grid[row][i] == -1) {
                    count++;
                }
            }
            if (count == length) {
                return false;
            }*/
            for (int i = col; i < col + length; i++) {
                if (grid[row][i] == 1 || grid[row][i] == -1) {
                    grid[row][i] = -1;
                    hasCrossing = true;
                    addRestriction(row, i);
                } else {
                    grid[row][i] = 1;
                }
            }
            quantity++;
        }
        return quantity == 1 || hasCrossing;
    }

    public boolean isNotFoundRestriction(int row, int col, int length, Orientation orientation) {
        if (Orientation.VERTICAL.equals(orientation)) {
            for (int i = row; i < row + length; i++) {
                if (grid[i][col] == NOT_AVAILABLE) {
                    return false;
                }
            }
        } else {
            for (int i = col; i < col + length; i++) {
                if (grid[row][i] == NOT_AVAILABLE) {
                    return false;
                }
            }
        }
        return true;
    }

    public void addRestriction(int row, int col) {
        if (row == 0) {
            if (col == 0) {
                grid[row + 1][col + 1] = NOT_AVAILABLE;
            } else if (col == COLUMN_COUNT - 1) {
                grid[row + 1][col - 1] = NOT_AVAILABLE;
            } else {
                grid[row + 1][col - 1] = NOT_AVAILABLE;
                grid[row + 1][col + 1] = NOT_AVAILABLE;
            }
        } else if (row == ROW_COUNT - 1) {
            if (col == 0) {
                grid[row - 1][col + 1] = NOT_AVAILABLE;
            } else if (col == COLUMN_COUNT - 1) {
                grid[row - 1][col - 1] = NOT_AVAILABLE;
            } else {
                grid[row - 1][col - 1] = NOT_AVAILABLE;
                grid[row - 1][col + 1] = NOT_AVAILABLE;
            }
        } else if (col == 0) {
            if (row > 0 && row < ROW_COUNT - 1) {
                grid[row - 1][col + 1] = NOT_AVAILABLE;
                grid[row + 1][col + 1] = NOT_AVAILABLE;
            }
        } else if (col == COLUMN_COUNT - 1) {
            if (row > 0 && row < ROW_COUNT - 1) {
                grid[row - 1][col - 1] = NOT_AVAILABLE;
                grid[row + 1][col - 1] = NOT_AVAILABLE;
            }
        } else {
            grid[row - 1][col + 1] = NOT_AVAILABLE;
            grid[row - 1][col - 1] = NOT_AVAILABLE;
            grid[row + 1][col + 1] = NOT_AVAILABLE;
            grid[row + 1][col - 1] = NOT_AVAILABLE;
        }
    }

    public void displayGrid() {
        for (int i = 0; i < ROW_COUNT; i++) {
            StringBuilder builder = new StringBuilder();
            for (int j = 0; j < COLUMN_COUNT; j++) {
                builder.append(grid[i][j]);
                if (j != COLUMN_COUNT - 1) {
                    builder.append(" ");
                }
            }
            System.out.println(builder.toString());
        }
    }

}
